package cn.edu.cug.cs.gtl.gsm.aof.ftp;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

import java.io.*;
import java.util.logging.Logger;

/**
 * @Author: jitao
 * @Date: 2022-07-02-21:29
 * @Description:
 */
public class SFTPStorageManager extends FTPBaseStorageManager {
    FTPUtils ftpUtils;
    Logger logger = Logger.getLogger("cn.edu.cug.cd.gtl.gsm.ftp.SFTPStorageManager");
    //数据文件输入流
    InputStream  dataFileIn;
    //数据文件输出流
    OutputStream dataFileOut;
    //索引文件输入流
    InputStream indexFileIn;
    //索引文件输出流
    OutputStream indexFileOut;
    //FTP客户端
    FTPClient ftpClient;
    //数据文件名字
    String dataFileName;
    //索引文件名字
    String indexFileName;

    int oldOrder = 0;
    /**
     * @param baseName
     * @param collectionSize
     * @param pageSize
     */
    public SFTPStorageManager(String baseName, long collectionSize, int pageSize, String workDirectory, boolean overWrite) throws IOException {
        super(baseName, collectionSize, pageSize);
        long length = 0;//记录文件的长度
        this.ftpUtils = new FTPUtils();
        this.ftpClient = ftpUtils.initFtpClient();
        this.ftpClient.changeWorkingDirectory(workDirectory);
        this.ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        this.dataFileName = baseName + "_0.txt";
        this.indexFileName = baseName + ".idx";
        //如果该文件在FTP服务器上不存在,则在服务器上创建该文件
        FTPFile[] ftpFiles = this.ftpClient.listFiles(dataFileName);
        if (ftpFiles.length <= 0) {
            File file = new File(dataFileName);
            file.createNewFile();
            FileInputStream fileInputStream = new FileInputStream(file);
            this.ftpClient.storeFile(dataFileName, fileInputStream);
            fileInputStream.close();
            logger.info("创建新的数据文件");
        }
        ftpFiles = this.ftpClient.listFiles(indexFileName);
        //如果远程服务器上没有索引文件，创建一个新的索引文件
        if (ftpFiles.length <= 0) {
            File file = new File(indexFileName);
            file.createNewFile();
            FileInputStream fileInputStream = new FileInputStream(file);
            this.ftpClient.storeFile(indexFileName, fileInputStream);
            fileInputStream.close();
            //再次获取索引文件
            ftpFiles = this.ftpClient.listFiles(indexFileName);
            logger.info("创建新的索引文件");
        }
        if (overWrite) {
            //索引文件输出流为覆盖模式
            this.indexFileOut = new DataOutputStream(this.ftpClient.storeFileStream(indexFileName));
            //如果要覆盖原有索引文件，那么直接将文件覆盖掉
            this.indexFileOut.write("".getBytes());
            this.indexFileOut.flush();
            this.indexFileOut.close();
            this.ftpClient.completePendingCommand();
            this.indexFileOut = null;
            //数据文件输出流为覆盖模式
            this.dataFileOut = this.ftpClient.storeFileStream(this.dataFileName);
            this.dataFileOut.write("".getBytes());
            this.dataFileOut.flush();
            this.dataFileOut.close();
            this.ftpClient.completePendingCommand();
            this.dataFileOut = null;
        }
        //获取当前索引文件的长度
        length = ftpFiles[0].getSize();

        if (length == 0 || overWrite == true) {//如果索引文件长度为0
            this.getNextPageIdentifier().reset(0);
        } else {
            //从索引文件中读取MetaItem
            readMetaFromStorage();
        }
        //如果已经存在不为空的索引信息
        if ((overWrite == false) && (length > 0)) {
            readIndicesFromStorage();
            this.indexFileIn.close();
            this.ftpClient.completePendingCommand();
            this.indexFileIn = null;
        }
    }

    @Override
    protected OutputStream getDataOutputStream(int order) {
        if (this.indexFileOut != null) {
            try {
                this.indexFileOut.close();
                this.ftpClient.completePendingCommand();
                this.indexFileOut = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
            //追加数据
            try {
                if (this.oldOrder != order) {
                    this.dataFileOut.close();
                    this.ftpClient.completePendingCommand();
                    this.dataFileOut = null;
                    this.oldOrder = order;
                    this.dataFileName = this.metaItem.getBaseName() + "_" + String.valueOf(this.getCurrentCollectionOrder()).toString() + ".txt";
                    FTPFile[] ftpFiles = this.ftpClient.listFiles(dataFileName);
                    if (ftpFiles.length <= 0) {
                        File file = new File(dataFileName);
                        file.createNewFile();
                        FileInputStream fileInputStream = new FileInputStream(file);
                        this.ftpClient.storeFile(dataFileName, fileInputStream);
                        fileInputStream.close();
                    }
                }
                if (this.dataFileOut == null) {
                    this.dataFileOut = this.ftpClient.appendFileStream(this.dataFileName);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        return this.dataFileOut;
    }

    @Override
    protected InputStream getDataInputStream(int order) {
        if (this.dataFileIn != null) {
            try {
                this.dataFileIn.close();
                this.ftpClient.completePendingCommand();
                this.dataFileIn = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            this.dataFileName = this.metaItem.getBaseName() + "_" + String.valueOf(this.getCurrentCollectionOrder()).toString() + ".txt";
            this.dataFileIn = this.ftpClient.retrieveFileStream(this.dataFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return this.dataFileIn;
    }

    @Override
    protected OutputStream getIndexOutputStream() {
        if (this.dataFileOut != null) {
            try {
                this.dataFileOut.close();
                this.ftpClient.completePendingCommand();
                this.dataFileOut = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (this.indexFileOut == null) {
            try {
                this.indexFileOut = ftpClient.storeFileStream(this.indexFileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return this.indexFileOut;
    }

    @Override
    protected InputStream getIndexInputStream() {
        if (this.indexFileIn == null) {
            try {
                this.indexFileIn = this.ftpClient.retrieveFileStream(indexFileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return this.indexFileIn;
    }
}
